import { RecordState } from "@/State/RecordState";
import { Table } from "@/Database/TableBuilder";

export class Database<T extends RecordState> {
  private readonly indexdbDB: IDBFactory;
  private database: IDBDatabase | null = null;
  private readonly table: Table;

  constructor(table: Table) {
    this.indexdbDB = window.indexedDB;
    this.table = table;
    this.openDatabase();
  }

  private openDatabase(): void {
    const open = this.indexdbDB.open(
      this.table.Database(),
      this.table.Version()
    );
    open.onupgradeneeded = (e: any) => {
      this.upgradeDatabase(e.target.result);
    };
    open.onsuccess = (e: any) => {
      this.database = e.target.result;
    };
  }

  private upgradeDatabase(database: IDBDatabase) {
    this.database = database;
    this.table.Build(database);
  }

  private getObjectStore(): IDBObjectStore | null {
    try {
      const transaction: IDBTransaction = this.database!.transaction(
        this.table.TableName(),
        "readwrite"
      );
      const dbStore: IDBObjectStore = transaction.objectStore(
        this.table.TableName()
      );
      return dbStore;
    } catch (Error) {
      console.log("get Object Store Error!" + Error);
      return null;
    }
  }

  public Create(state: T): Promise<void> {
    return new Promise<void>((resolve, reject) => {
      const dbStore = this.getObjectStore();
      const request: IDBRequest = dbStore!.add(state);
      request.onsuccess = (e: any) => {
        resolve(e);
      };

      request.onerror = (e: any) => {
        reject(e);
      };
    });
  }

  public ReadAll(): Promise<T[]> {
    return new Promise<T[]>((response, reject) => {
      const dbStore = this.getObjectStore();
      const items: T[] = new Array<T>();
      const request: IDBRequest = dbStore!.openCursor();
      request.onsuccess = (e: any) => {
        const cursor: IDBCursorWithValue = e.target.result;
        if (cursor) {
          const result: T = cursor.value;
          if (result.IsActive) {
            items.push(result);
          }
          cursor.continue();
        } else {
          response(items);
        }
      };
      request.onerror = (e: any) => {
        reject(e);
      };
    });
  }

  public Update(state: T): Promise<void> {
    return new Promise<void>((resolve, reject) => {
      const dbStore = this.getObjectStore();
      const innerRequest: IDBRequest = dbStore!.put(state);
      innerRequest.onsuccess = () => {
        resolve();
      };
    });
  }
}
